package sjtu.ist.warehouse4ws.epc2bpmn;


import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Element;


import sjtu.ist.warehouse4ws.model.Epcunit;
import sjtu.ist.warehouse4ws.model.Epcunits;
import sjtu.ist.warehouse4ws.tool.file.Util;

public class WriteUtil {
	private Document doc;
	private Epcunits sourceDatas;
	private String sourceRef;
	public WriteUtil(Document doc,Epcunits sourceDatas){
		this.doc=doc;
		this.sourceDatas=sourceDatas;
	}
	
	public String getSourceRef() {
		return sourceRef;
	}

	public void setSourceRef(String sourceRef) {
		this.sourceRef = sourceRef;
	}

	public Document getDoc() {
		return doc;
	}

	public void setDoc(Document doc) {
		this.doc = doc;
	}

	public Epcunits getSourceDatas() {
		return sourceDatas;
	}

	public void setSourceDatas(Epcunits sourceDatas) {
		this.sourceDatas = sourceDatas;
	}
    public void writeDefinitions(Element definitions){
    	

		//add attributes to the definitions
		definitions.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
		definitions.setAttribute("xsi:schemaLocation","http://schema.omg.org/spec/BPMN/2.0 " +
				"../../../../../../../../../../bpmn/src/main/resources/BPMN20.xsd" );
		definitions.setAttribute("xmlns","http://schema.omg.org/spec/BPMN/2.0");
		definitions.setAttribute("typeLanguage","http://www.w3.org/2001/XMLSchema");
		definitions.setAttribute("expressionLanguage","http://www.w3.org/1999/XPath");
		definitions.setAttribute("targetNamespace","http://jbpm.org/example/bpmn2/none_start_end_event");
		definitions.setAttribute("xmlns:jbpm","http://jbpm.org/bpmn2");
		
		
		doc.appendChild(definitions);
    }
	public void writeTask(Epcunit sourceData,Element process){
	    Element function=doc.createElement("userTask");
	    String functionId=Util.idStandardization(sourceData.getName());
	    function.setAttribute("id",functionId);
	    String functionName=Util.nameStandardization(functionId);
	    function.setAttribute("name",functionName);
	    function.setAttribute ("implementation","other");
	    
	    Element potentialOwner=doc.createElement("potentialOwner");
	    potentialOwner.setAttribute("resourceRef","user" );
	    potentialOwner.setAttribute("jbpm:type", "group");
	    
	    Element resourceAssignmentExpression=doc.createElement("resourceAssignmentExpression");
	    
	    String participant;
	    int participantId=sourceData.getParticipant();
	    Element formalExpression=doc.createElement("formalExpression");
	    if (participantId==0) {
	    	participant="user";
	    }
	   
	    else participant=sourceDatas.findSourceDataById(participantId).getName();
	    formalExpression.setTextContent(participant);
	    
	    resourceAssignmentExpression.appendChild(formalExpression);
	    potentialOwner.appendChild(resourceAssignmentExpression);
	    function.appendChild(potentialOwner);
	    process.appendChild(function);     //append function to the process
	   
	    sourceRef=sourceData.getName();   //update the latest task
	    
	    //write sequence
	    writeSequence(process,sourceData.getId());
	   
	}
	public void writeSequence(Element process,int id){
		  List <Epcunit>taskList=new ArrayList<Epcunit>();
		  sourceDatas.findNextFunction(id,taskList);
		    for (Epcunit task:taskList)
		    {
		    	
		    	 
			     Element sequence=doc.createElement("sequenceFlow");
			     String sequenceId;
			    
			    
			     if (task.getType()=="connector") {
			    	 sequenceId=Util.idStandardization(sourceRef+"GateWay");
			    	 sequence.setAttribute("targetRef",sourceRef+"GateWay");
			     }
			     
			     else {
			    	 sequenceId=task.getName();
			    	 sequence.setAttribute("targetRef",sequenceId);
			     }
                 sequence.setAttribute("id", "to_"+sequenceId);
			     
			     String sequenceName=Util.nameStandardization(sequenceId);
			     sequence.setAttribute("name","To "+sequenceName);
			     sequence.setAttribute("sourceRef",sourceRef );
			     
			     if (sourceRef.endsWith("GateWay")){ 
			     Element conditionExpression=doc.createElement("conditionExpression");
				 conditionExpression.setAttribute("xsi:type","tFormalExpression");
				
				  //some rules that need to put in
				  sequence.appendChild(conditionExpression);
				  }
			     process.appendChild(sequence);
		    }	
	}
	
	public void writeConnector(Epcunit sourceData,Element process){
		 Element connector = null;
		 
		 if  (sourceData.getName()=="xor")
		 {
			 connector=doc.createElement("exclusiveGateway");
		 }
		 else  if(sourceData.getName()=="and"){
			 connector=doc.createElement("parallelGateway");
		 }
		 String connectorId=sourceRef+"GateWay";
		 connector.setAttribute("id",connectorId);
		 String connectorName=Util.nameStandardization(connectorId);
		 connector.setAttribute("name",connectorName);
		 process.appendChild(connector);
		 
		 sourceRef=connectorId;
		 
		 //write sequence
		 writeSequence(process,sourceData.getId());
		 
		  
		  
	}
	public void write(){
		
		List <Epcunit>list=sourceDatas.getEpcUnits();
		// create definitions
		Element definitions=doc.createElement("definitions");
		writeDefinitions(definitions);
		
		// process
		Element process=doc.createElement("process");
		
		process.setAttribute("id", Util.idStandardization(list.get(0).getName()));
		process.setAttribute("name", Util.nameStandardization(list.get(0).getName()));
		definitions.appendChild(process);
		
		//startEvent
		Element startEvent=doc.createElement("startEvent");
		startEvent.setAttribute("id", "start");
		process.appendChild(startEvent);
		
		sourceRef="start";  //the latest task
		
		
		
		writeSequence(process,list.get(0).getId());
		
		int i=1;
		
		Epcunit sourceData=list.get(i);
		
		while (sourceData.getType() !="end"){
		
	           //write userTask		
			 if (sourceData.getType()=="function" )
				 writeTask(sourceData,process);
			
			 else if  (sourceData.getType()=="connector")
				 writeConnector(sourceData,process);
		    sourceData=list.get(++i);
			
		}
		
		Element endEvent=doc.createElement("endEvent");
		endEvent.setAttribute("id","end");
		endEvent.setAttribute("name","End");
		process.appendChild(endEvent);
	}

}
